package com.byd.model;

import java.util.LinkedList;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.NetworkInfo.State;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import com.byd.application.MyApplication;
import com.byd.utils.Lg;

public class NetManager extends BroadcastReceiver {
	public static NetManager sNetManager;
	public static final int NET_NONE = -1;
	public static final int NET_WIFI = 0;
	public static final int NET_MOBILE = 1;
	private Context mContext;
	private WifiManager mWifiManager;
	private final ConnectivityManager mConnectivityManager;
	private NetworkInfo mNetworkInfo;
	private int mNetState = NET_NONE;
	private final LinkedList<InternetAction> mActions;

	private NetManager() {
		mContext = MyApplication.getInstance();
		mActions = new LinkedList<InternetAction>();
		mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
		final IntentFilter filter = new IntentFilter();
		filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
		filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
		mContext.registerReceiver(this, filter);
		mConnectivityManager = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
		try {
			onNetStateChanged();
		}
		catch (final Exception e) {
			Lg.printStackTrace(e);
		}
	}

	public static synchronized NetManager getInstance() {
		if(sNetManager == null) {
			sNetManager = new NetManager();
		}
		return sNetManager;
	}

	@Override
	public void onReceive(Context context, Intent intent) {
		try {
			onNetStateChanged();
		}
		catch (final Exception e) {
			Lg.printStackTrace(e);
		}
	}

	private void onNetStateChanged() throws Exception {
		mNetworkInfo = mConnectivityManager.getActiveNetworkInfo();
		if(mNetworkInfo != null && mNetworkInfo.getState() == State.CONNECTED) {
			final WifiInfo wifi = mWifiManager.getConnectionInfo();
			final String extraInfo = String.valueOf(mNetworkInfo.getExtraInfo()).replaceAll("\"", "");
			final String ssid = (wifi == null ? "" : wifi.getSSID()).replaceAll("\"", "");
			if(extraInfo.equals(ssid)) {
				setNetState(NET_WIFI);
			}
			else {
				setNetState(NET_MOBILE);
			}
			checkAction();
		}
		else {
			setNetState(NET_NONE);
		}
	}

	private void setNetState(int state) throws Exception {
		if(mNetState != state) {
			mNetState = state;
			Lg.i("net state changed: " + state);
		}
	}

	public int getState() {
		return mNetState;
	}

	public boolean isEnabled() {
		return mNetState != NET_NONE;
	}

	public boolean isMobile() {
		return isEnabled() && mNetState == NET_MOBILE;
	}

	public void release() throws Exception {
		mActions.clear();
		mContext.unregisterReceiver(this);
		mContext = null;
		mWifiManager = null;
		mNetworkInfo = null;
	}

	public String getType() {
		switch (mNetState) {
		case NET_MOBILE:
			return "mobile";
		case NET_WIFI:
			return "wifi";
		default:
			return "none";
		}
	}

	public static abstract class InternetAction implements Runnable {
		private final String name;
		private final Object tag;
		private boolean valid;
		private boolean async;

		public InternetAction(String name, Object tag) {
			this.name = name;
			this.tag = tag;
		}

		public Object getTag() {
			return tag;
		}

		public boolean isValid() {
			return valid;
		}

		@Override
		public final void run() {
			Lg.d("internet enable, run " + name + ", " + tag);
			onRun();
		}

		public abstract void onRun();
	}

	public synchronized void post(InternetAction action) {
		if(!mActions.contains(action)) {
			mActions.add(action);
		}
		action.valid = true;
		checkAction();
	}

	public synchronized void postAsync(InternetAction action) {
		action.async = true;
		post(action);
	}

	public synchronized void remove(InternetAction action) {
		action.valid = false;
		mActions.remove(action);
	}

	private synchronized void checkAction() {
		if(isEnabled()) {
			InternetAction action;
			while (mActions.size() > 0) {
				action = mActions.removeFirst();
				if(action.async) {
					MyThreadPool.getInternetExecutors().execute(action);
				}
				else {
					action.run();
				}
			}
		}
	}

	@Override
	protected void finalize() throws Throwable {
		Lg.i("finalize: " + toString());
		super.finalize();
	}
}
